import * as bcrypt from 'bcrypt'
import { Injectable, Logger } from '@nestjs/common'

/**
 * 密码工具类
 * 统一处理密码加密、验证等操作
 */
@Injectable()
export class PasswordUtil {
  private readonly logger = new Logger(PasswordUtil.name)
  private readonly saltRounds = 12

  /**
   * 加密密码
   * @param password 明文密码
   * @returns 加密后的密码
   */
  async hashPassword(password: string): Promise<string> {
    try {
      return await bcrypt.hash(password, this.saltRounds)
    } catch (error) {
      this.logger.error(`密码加密失败: ${error.message}`, error.stack)
      throw new Error('密码加密失败')
    }
  }

  /**
   * 验证密码
   * @param password 明文密码
   * @param hashedPassword 加密后的密码
   * @returns 是否匹配
   */
  async comparePassword(password: string, hashedPassword: string): Promise<boolean> {
    try {
      return await bcrypt.compare(password, hashedPassword)
    } catch (error) {
      this.logger.error(`密码验证失败: ${error.message}`, error.stack)
      return false
    }
  }

  /**
   * 验证密码强度
   * @param password 密码
   * @returns 是否符合强度要求
   */
  validatePasswordStrength(password: string): { isValid: boolean; message?: string } {
    if (password.length < 8) {
      return { isValid: false, message: '密码长度至少8位' }
    }

    if (!/(?=.*[a-z])/.test(password)) {
      return { isValid: false, message: '密码必须包含小写字母' }
    }

    if (!/(?=.*[A-Z])/.test(password)) {
      return { isValid: false, message: '密码必须包含大写字母' }
    }

    if (!/(?=.*\d)/.test(password)) {
      return { isValid: false, message: '密码必须包含数字' }
    }

    if (!/(?=.*[@$!%*?&])/.test(password)) {
      return { isValid: false, message: '密码必须包含特殊字符(@$!%*?&)' }
    }

    return { isValid: true }
  }

  /**
   * 生成随机密码
   * @param length 密码长度
   * @returns 随机密码
   */
  generateRandomPassword(length: number = 12): string {
    const charset = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789@$!%*?&'
    let password = ''

    // 确保包含各种字符类型
    password += 'a' // 小写字母
    password += 'A' // 大写字母
    password += '1' // 数字
    password += '@' // 特殊字符

    // 填充剩余长度
    for (let i = 4; i < length; i++) {
      password += charset.charAt(Math.floor(Math.random() * charset.length))
    }

    // 打乱字符顺序
    return password
      .split('')
      .sort(() => Math.random() - 0.5)
      .join('')
  }
}
